package com.zlc.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.zlc.common.common.entity.PageVo;
import com.zlc.common.common.exception.BusinessException;
import com.zlc.common.common.service.AutowiredService;
import com.zlc.common.core.resource.model.entity.MayanPlatSystem;
import com.zlc.common.core.resource.model.entity.MayanPlatSystemResource;
import com.zlc.common.core.resource.model.vo.MayanPlatSystemResourceVo;
import com.zlc.common.core.resource.model.vo.MayanPlatSystemVo;
import com.zlc.common.model.resource.SystemPageRequest;
import com.zlc.common.util.*;
import com.zlc.common.model.resource.ResourceEntity;
import com.zlc.common.util.tree.TreeUtil;
import com.zlc.platform.service.ResourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import static com.zlc.common.common.constant.PlatConstant.*;
import static com.zlc.common.common.constant.PlatformRedisConstant.MAYAN_SYSTEM_RESOURCE_CACHE;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class ResourceServiceImpl extends AutowiredService implements ResourceService {


    @Override
    public List<MayanPlatSystemVo> queryAllSystem() {
        LambdaQueryWrapper<MayanPlatSystem> wrapper = mayanPlatSystemService.wrapper();
        wrapper.orderByAsc(MayanPlatSystem::getCreateTime);
        return mayanPlatSystemService.queryVoList(wrapper);
    }

    @Override
    public PageVo<MayanPlatSystemVo> querySystem(SystemPageRequest request) {
        PageHelper.startPage(request.getPageNum(),request.getPageSize());
        List<MayanPlatSystemVo> mayanPlatSystemVos = mayanPlatSystemMapper.queryList(request);
        return PageVo.page(mayanPlatSystemVos);
    }

    @Override
    public void addSystem(MayanPlatSystemVo system) {
        String systemCode = system.getSystemCode();
        MayanPlatSystemVo oldSystem = mayanPlatSystemService.getBySystemCode(systemCode);
        AssertUtils.isTrue(ObjectUtils.isEmpty(oldSystem),"系统已存在");
        mayanPlatSystemService.saveVo(system);
    }

    @Override
    public void updateSystem(MayanPlatSystemVo systemVo) {
        mayanPlatSystemService.saveVo(systemVo);
    }

    @Override
    public void removeSystem(String id) {
        MayanPlatSystem system = mayanPlatSystemService.getById(id);
        if(!ObjectUtils.isEmpty(system)){
            LambdaQueryWrapper<MayanPlatSystemResource> wrapper = mayanPlatSystemResourceService.wrapper();
            wrapper.eq(MayanPlatSystemResource::getSystemCode,system.getSystemCode());
            List<MayanPlatSystemResourceVo> resourceVos = mayanPlatSystemResourceService.queryVoList(wrapper);
            if(!ObjectUtils.isEmpty(resourceVos)){
                throw new BusinessException("系统存在资源不可删除");
            }
            mayanPlatSystemService.removeById(id);
        }
    }

    @Override
    public ResourceEntity queryResource(String systemCode) {
        List<ResourceEntity> resourceEntities = loadResource(systemCode);
        return ObjectUtils.isEmpty(resourceEntities) ? null : resourceEntities.get(0);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<ResourceEntity> queryAllResource() {
        String cache = RedisUtils.get(MAYAN_SYSTEM_RESOURCE_CACHE);
        if(!ObjectUtils.isEmpty(cache)){
            try {
                return JsonHelper.parseJson(cache, List.class, ResourceEntity.class);
            }catch (Exception e){
                //此处拒绝抛出异常，如果失败，直接获取数据库
            }
        }
        List<ResourceEntity> entities = loadResource(null);
        RedisUtils.set(MAYAN_SYSTEM_RESOURCE_CACHE, JsonHelper.toJson(entities),24 * 3600L);
        return entities;
    }

    @SuppressWarnings("unchecked")
    private List<ResourceEntity> loadResource(String systemCode){
        //返回值
        List<ResourceEntity> entities = new ArrayList<>();
        //查询所有系统
        LambdaQueryWrapper<MayanPlatSystem> systemWrapper = new LambdaQueryWrapper<>();
        if(!ObjectUtils.isEmpty(systemCode)){
            systemWrapper.eq(MayanPlatSystem::getSystemCode,systemCode);
        }
        systemWrapper.orderByAsc(MayanPlatSystem::getCreateTime);
        List<MayanPlatSystem> list = mayanPlatSystemService.list(systemWrapper);
        //查询所有资源
        List<String> systemCodes = list.stream().map(MayanPlatSystem::getSystemCode).collect(Collectors.toList());
        LambdaQueryWrapper<MayanPlatSystemResource> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(MayanPlatSystemResource::getSystemCode,systemCodes);
        List<MayanPlatSystemResourceVo> resources = mayanPlatSystemResourceService.queryVoList(queryWrapper);
        for(MayanPlatSystem system : list){
            ResourceEntity entity = new ResourceEntity();
            entity.setIcon(system.getIcon());
            entity.setResourceName(system.getSystemName());
            entity.setSystemCode(system.getSystemCode());
            entity.setResourceType("SYSTEM");
            entity.setDisabled(Boolean.TRUE);
            entity.setUrlPath(system.getUrl());
            //查询系统下的所有资源
            List<MayanPlatSystemResourceVo> systemResourceList = resources.stream()
                    .filter(r -> r.getSystemCode() != null && r.getSystemCode().equals(system.getSystemCode()))
                    .collect(Collectors.toList());
            ResourceEntity web = new ResourceEntity();
            web.setResourceName(RESOURCE_CATEGORY_WEB);
            web.setSystemCode(system.getSystemCode());
            web.setResourceCategory(RESOURCE_CATEGORY_WEB);
            web.setDisabled(Boolean.TRUE);
            web.setResourceType("CATEGORY");
            web.setResourceCode(system.getSystemCode()+"WEB");
            ResourceEntity app = new ResourceEntity();
            app.setResourceName(RESOURCE_CATEGORY_APP);
            app.setSystemCode(system.getSystemCode());
            app.setResourceCategory(RESOURCE_CATEGORY_APP);
            app.setResourceType("CATEGORY");
            app.setDisabled(Boolean.TRUE);
            app.setResourceCode(system.getSystemCode()+"APP");
            if(!ObjectUtils.isEmpty(systemResourceList)){
                //获取WEB端
                List<MayanPlatSystemResourceVo> webResourceList = systemResourceList.stream()
                        .filter(s -> RESOURCE_CATEGORY_WEB.equals(s.getResourceCategory())).collect(Collectors.toList());
                loadResourceEntity(web,webResourceList);

                //获取APP端
                List<MayanPlatSystemResourceVo> appResourceList = systemResourceList.stream()
                        .filter(s -> RESOURCE_CATEGORY_APP.equals(s.getResourceCategory())).collect(Collectors.toList());
                loadResourceEntity(app,appResourceList);
            }
            entity.getChildren().add(web);
            entity.getChildren().add(app);
            entities.add(entity);
        }
        return entities;
    }


    private void loadResourceEntity(ResourceEntity entity,List<MayanPlatSystemResourceVo> systemResourceList){
        List<ResourceEntity> resourceEntities = BeanCopyUtils.copyObjList(systemResourceList,ResourceEntity.class);
        resourceEntities.forEach(s->{
            if(ObjectUtils.isEmpty(s.getOrder())){
                s.setOrder(0);
            }
            s.setSortNum(s.getOrder());
            s.setParentCode(s.getParentResourceId());
            s.setCode(s.getResourceId());
        });
        List<ResourceEntity> children = TreeUtil.buildTree(resourceEntities);
        entity.setChildren(children);
    }

    @Override
    public MayanPlatSystemResourceVo addResource(MayanPlatSystemResourceVo resourceVo) {
        RedisUtils.delete(MAYAN_SYSTEM_RESOURCE_CACHE);
        if(ObjectUtils.isEmpty(resourceVo.getResourceId())){
            resourceVo.setResourceId(PlatUtils.uuid());
        }
        String resourceCategory = resourceVo.getResourceCategory();
        String resourceType = resourceVo.getResourceType();
        if(!Arrays.asList(RESOURCE_CATEGORY_APP,RESOURCE_CATEGORY_WEB).contains(resourceCategory)){
            throw new BusinessException("资源类别错误,只能是WEB|APP");
        }
        if(!Arrays.asList(RESOURCE_TYPE_MENU,RESOURCE_TYPE_GROUP,RESOURCE_TYPE_SUBMENU,RESOURCE_TYPE_BUTTON).contains(resourceType)){
            throw new BusinessException("资源类型错误,只能是MENU|GROUP|SUBMENU");
        }
        if(!ObjectUtils.isEmpty(resourceVo.getParentResourceId())){
            LambdaQueryWrapper<MayanPlatSystemResource> wrapper = mayanPlatSystemResourceService.wrapper();
            wrapper.eq(MayanPlatSystemResource::getResourceId,resourceVo.getParentResourceId());
            MayanPlatSystemResourceVo parentResource = mayanPlatSystemResourceService.queryOne(wrapper);
            AssertUtils.isTrue(!ObjectUtils.isEmpty(parentResource),"父资源"+resourceVo.getParentResourceId()+"不存在");
        }
        return mayanPlatSystemResourceService.saveVo(resourceVo);
    }

    @Override
    public MayanPlatSystemResourceVo queryByResourceId(String resourceId) {
        LambdaQueryWrapper<MayanPlatSystemResource> wrapper = mayanPlatSystemResourceService.wrapper();
        wrapper.eq(MayanPlatSystemResource::getResourceId,resourceId);
        return mayanPlatSystemResourceService.queryOne(wrapper);
    }

    @Override
    public MayanPlatSystemResourceVo updateResource(MayanPlatSystemResourceVo resourceVo) {
        RedisUtils.delete(MAYAN_SYSTEM_RESOURCE_CACHE);
        AssertUtils.isTrue(!ObjectUtils.isEmpty(resourceVo.getId()),"主键不可为空");
        if(ObjectUtils.isEmpty(resourceVo.getResourceId())){
            throw new BusinessException("资源ID不可为空");
        }
        String resourceCategory = resourceVo.getResourceCategory();
        String resourceType = resourceVo.getResourceType();
        if(!Arrays.asList(RESOURCE_CATEGORY_APP,RESOURCE_CATEGORY_WEB).contains(resourceCategory)){
            throw new BusinessException("资源类别错误,只能是WEB|APP");
        }
        if(!Arrays.asList(RESOURCE_TYPE_MENU,RESOURCE_TYPE_GROUP,RESOURCE_TYPE_SUBMENU,RESOURCE_TYPE_BUTTON).contains(resourceType)){
            throw new BusinessException("资源类型错误,只能是MENU|GROUP|SUBMENU");
        }
        if(!ObjectUtils.isEmpty(resourceVo.getParentResourceId())){
            LambdaQueryWrapper<MayanPlatSystemResource> wrapper = mayanPlatSystemResourceService.wrapper();
            wrapper.eq(MayanPlatSystemResource::getResourceId,resourceVo.getParentResourceId());
            MayanPlatSystemResourceVo parentResource = mayanPlatSystemResourceService.queryOne(wrapper);
            AssertUtils.isTrue(!ObjectUtils.isEmpty(parentResource),"父资源"+resourceVo.getParentResourceId()+"不存在");
        }
        return mayanPlatSystemResourceService.saveVo(resourceVo);
    }

    @Override
    public void removeResource(String resourceId) {
        mayanPlatSystemResourceMapper.deleteByResourceId(resourceId);
        mayanPlatResourceRoleMapper.deleteByResourceId(resourceId);
        RedisUtils.delete(MAYAN_SYSTEM_RESOURCE_CACHE);
    }
}
